package statemachine;

import java.lang.annotation.Annotation;

import router.Interface.NetworkTypes;
import dataStructures.*;


/**
 * Diese Klasse realisiert den Nachbarschafts Zustandsautomaten des OSPF Protokolls. Im Konstruktor werden die entsprechenden Zustände erzeugt und die Zustandsübergänge definiert.
 * -Singleton-
 * @author Pascal Staudenrauss
 *
 */
public final class NeighborStateMachine extends AbstractStateMachine {
	
	private static NeighborStateMachine instance = null;
	
	public static NeighborStateMachine getInstance(){
		if(instance == null){
			instance = new NeighborStateMachine();
		}
		return instance;
	}
	
	/**
	 * 
	 */
	private NeighborStateMachine(){
		this.addState(new State("Down"));
		this.addState(new State("Attempt"));
		this.addState(new State("Init"));
		this.addState(new State("2Way"));
		this.addState(new State("ExStart"));
		this.addState(new State("Exchange"));
		this.addState(new State("Loading"));
		this.addState(new State("Full"));
		
		//Decision Points
		this.addState(new DecisionPoint("DP1"){
			@Override
			public State decide(NeighborDataStructure neighbor) {
				NetworkTypes neighborsType = neighbor.getAttachedInterface().getNetworkType();
				if(neighborsType.equals(NetworkTypes.pointToMultiPoint) || neighborsType.equals(NetworkTypes.pointToPoint) || neighborsType.equals(NetworkTypes.virtualLink)
						|| neighbor.getAttachedInterface().getState().toString() == "BDR" || neighbor.getAttachedInterface().getState().toString() == "DR"
							|| neighbor.getBDR().equals(neighbor.getNeighborID()) || neighbor.getDR().equals(neighbor.getNeighborID())){
					
					neighbor.setState(NeighborStateMachine.getInstance().getStateByName("ExStart"));
					return (State) NeighborStateMachine.getInstance().getStateByName("ExStart");
				}
				
				else{
					neighbor.setState(NeighborStateMachine.getInstance().getStateByName("2-Way"));
					return (State) NeighborStateMachine.getInstance().getStateByName("2-Way");
				}
				
			}
		});
		
		this.addState(new DecisionPoint("DP2"){
			@Override
			public State decide(NeighborDataStructure neighbor) {
				if(neighbor.getLinkStateRequestList().isEmpty()){
					neighbor.setState(NeighborStateMachine.getInstance().getStateByName("Full"));
					return (State) NeighborStateMachine.getInstance().getStateByName("Full");
				}
				else{
					neighbor.setState(NeighborStateMachine.getInstance().getStateByName("Loading"));
					return (State) NeighborStateMachine.getInstance().getStateByName("Loading");
				}
			}
		});
		
		this.addState(new DecisionPoint("DP3"){
			@Override
			public State decide(NeighborDataStructure neighbor) {
				neighbor.setState(NeighborStateMachine.getInstance().getStateByName("Exchange"));
				return (State) NeighborStateMachine.getInstance().getStateByName("Exchange");
			}
		});
		
		
		
		
		
		
		this.addWordToAlphabet("IE1", "nur bei NBMA Nachbarn");
		this.addWordToAlphabet("IE2", "Hello Packet von Nachbar erhalten");
		this.addWordToAlphabet("IE3", "Kein Hello Packet erhalten");
		this.addWordToAlphabet("IE4", "Router sieht eigene ID im Hello Packet des Nachbarn");
		this.addWordToAlphabet("IE5", "Nachbar sollte nicht Adjazent werde");
		this.addWordToAlphabet("IE6", "Schaltet wenn sich Nachbar in 2-Way befindet oder der Interface Zustand sich aendert");
		this.addWordToAlphabet("IE7", "Mit diesem Nachbarn sollte eine Adjazenz eingegangen werden");
		this.addWordToAlphabet("IE8", "MasterSlave Beziehung eingegangen und DD SequenzNummern wurden ausgetauscht");
		this.addWordToAlphabet("IE9", "Database Description Packete wurden vollständig ausgetauscht");
		this.addWordToAlphabet("IE10", "In der Link State Request Liste existieren Eintraege");
		this.addWordToAlphabet("IE11", "Die LS Request Liste ist leer");
		this.addWordToAlphabet("IE12", "Adjazenz abbrechen");
		this.addWordToAlphabet("IE13", "Hello Packet erhalten, eigene ID steht nicht darin");
		this.addWordToAlphabet("IE14", "Interface Zustand hat sich geaendert");
		this.addWordToAlphabet("IE15", "Mit diesem Nachbarn weiterhin eine Adjazenz eingehen");
		this.addWordToAlphabet("IE16", "Adjazenz abbrechen");
		
		//Transitionen von Down zu...
		addTransition(getStateByName("Down"), "IE1", getStateByName("Attempt"));
		addTransition(getStateByName("Down"), "IE2", getStateByName("Init"));
		addTransition(getStateByName("Down"), "IE4", getStateByName("ExStart"));
		
		//Transition von Attempt zu...
		addTransition(getStateByName("Attempt"), "IE3", getStateByName("Down"));
		addTransition(getStateByName("Attempt"), "IE2", getStateByName("Init"));
		
		//Transition von Init zu...
		addTransition(getStateByName("Init"), "IE3", getStateByName("Down"));
		addTransition(getStateByName("Init"), "IE2", getStateByName("Init"));
		addTransition(getStateByName("Init"), "IE13", getStateByName("Init"));
		
		//Transition von  2Way zu...
		addTransition(getStateByName("2Way"), "IE3", getStateByName("Down"));
		addTransition(getStateByName("2Way"), "IE2", getStateByName("2Way"));
		addTransition(getStateByName("2Way"), "IE6", getStateByName("DP1"));
		addTransition(getStateByName("2Way"), "IE13", getStateByName("Init"));
		
		//Transition von ExStart zu...
		addTransition(getStateByName("ExStart"), "IE3", getStateByName("Down"));
		addTransition(getStateByName("ExStart"), "IE2", getStateByName("ExStart"));
		
		//Transition von Exchange zu...
		addTransition(getStateByName("Exchange"), "IE3", getStateByName("Down"));
		addTransition(getStateByName("Exchange"), "IE2", getStateByName("Exchange"));
		addTransition(getStateByName("Exchange"), "IE14", getStateByName("DP3"));
		addTransition(getStateByName("Exchange"), "IE12", getStateByName("ExStart"));
		addTransition(getStateByName("Exchange"), "IE9", getStateByName("DP2"));
		addTransition(getStateByName("Exchange"), "IE13", getStateByName("Init"));
		
		//Transition von Loading zu...
		addTransition(getStateByName("Loading"), "IE3", getStateByName("Down"));
		addTransition(getStateByName("Loading"), "IE2", getStateByName("Loading"));
		addTransition(getStateByName("Loading"), "IE14", getStateByName("DP3"));
		addTransition(getStateByName("Loading"), "IE13", getStateByName("Init"));
		addTransition(getStateByName("Loading"), "IE11", getStateByName("Full"));
		addTransition(getStateByName("Loading"), "IE12", getStateByName("ExStart"));
		
		//Transition von Full zu...
		addTransition(getStateByName("Full"), "IE3", getStateByName("Down"));
		addTransition(getStateByName("Full"), "IE2", getStateByName("Full"));
		addTransition(getStateByName("Full"), "IE13", getStateByName("Init"));
		addTransition(getStateByName("Full"), "IE12", getStateByName("ExStart"));
		addTransition(getStateByName("Full"), "IE14", getStateByName("DP3"));
		
		
	}

}
